{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2\n",
    "import sys\n",
    "import os\n",
    "import facenet\n",
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "import align.detect_face\n",
    "import pickle\n",
    "from sklearn.svm import SVC\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "minsize = 20 # minimum size of face\n",
    "threshold = [ 0.6, 0.7, 0.7 ]  # three steps's threshold\n",
    "factor = 0.709 # scale factor\n",
    "image_size = 160\n",
    "        \n",
    "with tf.Graph().as_default():\n",
    "    gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.9)\n",
    "    sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False))\n",
    "    with sess.as_default():\n",
    "        # 第一个预训练模型 ---> mtcnn ----> 人脸检测\n",
    "        pnet, rnet, onet = align.detect_face.create_mtcnn(sess, None)  #第二个参数存放模型所在目录  \n",
    "        \n",
    "        # 第二个预训练模型 ---> facenet ----> 人脸识别，主要是输出512维的特征值，作为第三个模型的输入\n",
    "        # 加载模型,模型位于models目录下\n",
    "        print('Loading feature extraction model')\n",
    "        facenet.load_model('models')\n",
    "            \n",
    "        # 获取输入和输出 tensors\n",
    "        images_placeholder = tf.get_default_graph().get_tensor_by_name(\"input:0\")\n",
    "        embeddings = tf.get_default_graph().get_tensor_by_name(\"embeddings:0\")\n",
    "        phase_train_placeholder = tf.get_default_graph().get_tensor_by_name(\"phase_train:0\")\n",
    "        embedding_size = embeddings.get_shape()[1]\n",
    "\n",
    "        # 第三个预训练模型 ---> facenet ----> 人脸识别分类\n",
    "        classifier_filename_exp = os.path.expanduser('new_models.pkl')\n",
    "        with open(classifier_filename_exp, 'rb') as infile:\n",
    "            (model, class_names) = pickle.load(infile)\n",
    "            print(class_names)\n",
    "            \n",
    "        print('Loaded classifier model from file \"%s\"' % classifier_filename_exp)\n",
    "\n",
    "        video_capture = cv2.VideoCapture(0)\n",
    "        capture_interval = 5\n",
    "        capture_count = 0\n",
    "        frame_count = 0 \n",
    "\n",
    "        while True:\n",
    "\n",
    "            ret, frame = video_capture.read()\n",
    "    \n",
    "            #每3帧采集一张人脸\n",
    "            if(capture_count%capture_interval == 0): \n",
    "                \n",
    "                gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
    "                if gray.ndim == 2:\n",
    "                    gray = facenet.to_rgb(gray)\n",
    "                \n",
    "                # 检测出人脸框和5个特征点\n",
    "                bounding_boxes, points = align.detect_face.detect_face(gray, minsize, pnet, rnet, onet, threshold, factor)\n",
    "                nrof_faces = bounding_boxes.shape[0]\n",
    "                \n",
    "                for face_position in bounding_boxes: \n",
    "                    face_position = face_position.astype(int)\n",
    "\n",
    "                    #裁剪出人脸区域作为第二个模型的输入\n",
    "                    cropped = gray[face_position[1]:face_position[3],face_position[0]:face_position[2],:]\n",
    "                    #丢弃\n",
    "                    if cropped.shape[0] == 0 or cropped.shape[1] == 0:\n",
    "                        continue\n",
    "                    \n",
    "                    scaled = cv2.resize(cropped, (image_size, image_size), interpolation=cv2.INTER_CUBIC )\n",
    "                    plt.imshow(scaled)\n",
    "                    scaled = scaled.reshape(-1,image_size,image_size,3)\n",
    "                    \n",
    "                    feed_dict = {images_placeholder:scaled, phase_train_placeholder:False }\n",
    "                    emb_array = sess.run(embeddings, feed_dict=feed_dict)\n",
    "        \n",
    "                    predictions = model.predict_proba(emb_array)\n",
    "                    print(predictions) \n",
    "                    predict = model.predict(emb_array) \n",
    "                    print(predict) \n",
    "                    \n",
    "                    #画人脸矩形框并标示类别\n",
    "                    cv2.rectangle(frame, (face_position[0], \n",
    "                                  face_position[1]), \n",
    "                                  (face_position[2], face_position[3]), \n",
    "                                  (255, 255, 0), 2)\n",
    "                    cv2.putText(frame,class_names[predict[0]], (face_position[0],face_position[1]), \n",
    "                                cv2.FONT_HERSHEY_COMPLEX_SMALL, 2, (255, 0 ,0), \n",
    "                                thickness = 2, lineType = 2)       \n",
    "                          \n",
    "                frame_count += 1\n",
    "                \n",
    "                #画出特征点\n",
    "                #print(points)\n",
    "                #print(points.shape)\n",
    "                if points.shape[0] != 0:\n",
    "                    for i in range(points.shape[1]):\n",
    "                        count = points.shape[0]/2\n",
    "                        count = int(count)\n",
    "                        for j in range(count):\n",
    "                            cv2.circle(frame, (points[j][i], points[j+count][i]), 3, (255,255,0),-1)\n",
    "                \n",
    "            capture_count += 1\n",
    "            cv2.imshow('Video', frame)\n",
    "    \n",
    "            if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "                break\n",
    "\n",
    "    video_capture.release()\n",
    "    cv2.destroyAllWindows()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
